﻿using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Lbb.Data
{
    /// <summary>
    /// 数据库操作基类
    /// </summary>
    /// Author          Chiron
    /// CreateDate      2011-5-11
    /// LastEditDate    2011-5-16
    public class RepositoryBase : IRepositroy, IDisposable
    {
        #region 字段
        private DataContext db;
        #endregion

        #region 属性
        /// <summary>
        /// 获取数据库对象。
        /// </summary>
        public virtual DataContext DB { get { return db; } protected set { db = value; } }
        #endregion

        #region 构造器

        /// <summary>
        /// 构造数据库操作类实例
        /// </summary>
        /// <param name="connStr">自定义连接串</param>
        public RepositoryBase(DataContext db)
        {
            this.db = db;
        }

        public RepositoryBase()
        {
        }

        #endregion

        #region 方法
        /// <summary>
        /// 检查参数。
        /// </summary>
        /// <param name="obj"></param>
        protected static void CheckArg(object obj, string name = "obj")
        {
            if (obj == null) throw new ArgumentNullException(name);
        }
        /// <summary>
        /// 删除记录
        /// </summary>
        /// <param name="obj"></param>
        /// chiron  2011-8-22
        public virtual void Delete(object obj)
        {
            CheckArg(obj);
            var table = db.GetTable(obj.GetType());
            if (table == null) throw new ArgumentException("找不到相关表!", "obj");
            table.DeleteOnSubmit(obj);
        }

        /// <summary>
        /// 删除记录集
        /// </summary>
        /// <param name="objs"></param>
        /// chiron  2011-8-22
        public virtual void DeleteRange(IEnumerable<object> objs)
        {
            CheckArg(objs, "objs");
            foreach (var obj in objs)
            {
                Delete(obj);
            }
        }

        /// <summary>
        /// 应用当前更改。
        /// </summary>
        public virtual void Save()
        {
            lock (db)
            {
                try
                {
                    DB.SubmitChanges();
                }
                catch (InvalidOperationException ex)
                {

                    DB.ChangeConflicts.ResolveAll(RefreshMode.KeepChanges);

                    DB.SubmitChanges();
                }
            }
        }
        #endregion

        #region IDisposable 成员
        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            DB.Dispose();
        }

        #endregion
    }
    /// <summary>
    /// 拓展操作库.
    /// </summary>
    /// Author      Chiron
    /// Created     2011-6-14
    /// LastUpdated 2011-6-14
    public static class ExtRepositoryBase
    {
        /// <summary>
        /// 获得部分记录。
        /// </summary>
        /// <param name="data">记录集。</param>
        /// <param name="startIndex">开始位置。</param>
        /// <param name="size">记录个数。</param>
        /// <param name="total">记录集中的记录总数。</param>
        /// <returns></returns>
        public static IQueryable<T> GetPartialData<T>(this IQueryable<T> data, int startIndex, int size, out int total) where T : class
        {
            if (data == null) throw new ArgumentNullException("data");
            total = data.Count();
            return data.Skip(startIndex).Take(size);
        }
        /// <summary>
        /// 获得部分记录。
        /// </summary>
        /// <param name="data">记录集。</param>
        /// <param name="startIndex">开始位置。</param>
        /// <param name="size">记录个数。</param>
        /// <param name="total">记录集中的记录总数。</param>
        /// <returns></returns>
        public static IEnumerable<T> GetPartialData<T>(this IEnumerable<T> data, int startIndex, int size, out int total) where T : class
        {
            if (data == null) throw new ArgumentNullException("data");
            total = data.Count();
            return data.Skip(startIndex).Take(size);
        }
    }
    /// <summary>
    /// 删除事件参数
    /// </summary>
    /// <typeparam name="T">记录类型</typeparam>
    /// Author      Chiron  2011-8-5
    public class DeletedRecordEventArgs<T> : EventArgs where T : class
    {
        /// <summary>
        /// 被删除的记录
        /// </summary>
        public T Record { get; set; }

    }
    /// <summary>
    /// 抽象操作库
    /// </summary>
    /// <typeparam name="T">
    /// 类
    /// </typeparam>
    /// Author      Chiron
    /// Created     2011-5-19
    /// LastUpdated 2011-6-27
    public abstract class RepositoryBase<T> : RepositoryBase, IRepositroy<T> where T : class
    {
        #region Events
        /// <summary>
        /// 记录被删除事件
        /// </summary>
        public event EventHandler<DeletedRecordEventArgs<T>> Deleted;
        #endregion


        public RepositoryBase(DataContext db)
            : base(db)
        {
            Table = db.GetTable<T>();
        }

        /// <summary>
        /// 当前操作的表.
        /// </summary>
        public Table<T> Table { get; private set; }



        /// <summary>
        /// 获得部分记录。
        /// </summary>
        /// <param name="data">记录集。</param>
        /// <param name="startIndex">开始位置。</param>
        /// <param name="size">记录个数。</param>
        /// <param name="total">记录集中的记录总数。</param>
        /// <returns></returns>
        protected static IQueryable<T> GetPartialData(IQueryable<T> data, int startIndex, int size, out int total)
        {
            return data.GetPartialData(startIndex, size, out total);
        }
        /*
        /// <summary>
        /// 搜索所有文本字段.
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        protected static IQueryable<T> FindAllTextField(IQueryable<T> data)
        {
            foreach (var p in DATA_PROPS.Where(p => p.PropertyType == typeof(string)))
            {
                data = data.Where(d => d[p.Name]);
            }
            return data;
        }
        */

        protected static string EditDefValue(string oldValue)
        {
            return string.IsNullOrEmpty(oldValue) ? notEmpty : string.Empty;
        }
        private const string notEmpty = " ";

        /// <summary>
        /// T 类的所有公有属性.
        /// </summary>
        public readonly static PropertyInfo[] DATA_PROPS = typeof(T).GetProperties();

        /// <summary>
        /// 取得指定记录.
        /// </summary>
        /// <param name="conditions">条件.</param>
        /// <returns></returns>
        /// chiron  2011-6-27
        public virtual T Get(Expression<Func<T, bool>> conditions)
        {
            return Table.FirstOrDefault(conditions);
        }
        /// <summary>
        /// 搜索记录.
        /// </summary>
        /// <param name="conditions">条件</param>
        /// <returns></returns>
        /// chiron  2011-6-27
        public virtual IQueryable<T> Find(Expression<Func<T, bool>> conditions)
        {
            return GetAll().Where(conditions);
        }

        /// <summary>
        /// 取得所有记录.
        /// </summary>
        /// <returns></returns>
        public virtual IQueryable<T> GetAll()
        {
            return Table;
        }

        /// <summary>
        /// 取得部分记录.
        /// </summary>
        /// <param name="startIndex">开始位置.</param>
        /// <param name="size">记录个数.</param>
        /// <param name="total">记录总数.</param>
        /// <returns></returns>
        public virtual IQueryable<T> GetAll(int startIndex, int size, out int total)
        {
            return GetPartialData(GetAll(), startIndex, size, out total);
        }

        /// <summary>
        /// 添加记录.
        /// </summary>
        /// <param name="obj"></param>
        public virtual void Add(T obj)
        {
            CheckArg(obj);
            Table.InsertOnSubmit(obj);
        }

        /// <summary>
        /// 添加多个记录.
        /// </summary>
        /// <param name="objs"></param>
        public virtual void AddRange(IEnumerable<T> objs)
        {
            if (objs == null) throw new ArgumentNullException("objs");
            foreach (var obj in objs)
            {
                Add(obj);
            }
        }

        /// <summary>
        /// 更新记录.
        /// </summary>
        /// <param name="obj"></param>
        public abstract void Update(T obj);

        /// <summary>
        /// 更新多个记录.
        /// </summary>
        /// <param name="objs"></param>
        public virtual void UpdateRange(IEnumerable<T> objs)
        {
            if (objs == null) throw new ArgumentNullException("objs");
            foreach (var obj in objs)
            {
                Update(obj);
            }
        }

        /// <summary>
        /// 删除记录.
        /// </summary>
        /// <param name="obj"></param>
        public virtual void Delete(T obj)
        {
            CheckArg(obj);
            if (Deleted != null)
            {
                Deleted.Invoke(this, new DeletedRecordEventArgs<T> { Record = obj });
            }
            Table.DeleteOnSubmit(obj);
        }

        /// <summary>
        /// 删除多个记录.
        /// </summary>
        /// <param name="objs"></param>
        public virtual void DeleteRange(IEnumerable<T> objs)
        {
            if (objs == null) throw new ArgumentNullException("objs");
            foreach (var obj in objs)
            {
                Delete(obj);
            }
        }
    }


}
